import { CdkDrag, CdkDropList, CdkDropListGroup, CdkDragEnter, CdkDragDrop } from '@angular/cdk/drag-drop';
import { NgClass, NgStyle } from '@angular/common';
import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core';

import { DraggableDirective } from '@app/shared/directives/draggable.directive';
import { DroppableDirective } from '@app/shared/directives/droppable.directive';
import { ResizableModule, ResizeEvent } from 'angular-resizable-element';
import { uniqueId } from 'lodash';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
import { NzGridModule } from 'ng-zorro-antd/grid';
import { NzIconDirective } from 'ng-zorro-antd/icon';
import { NzTabsModule } from 'ng-zorro-antd/tabs';

import { ConfigPanelComponent } from '../config-panel/config-panel.component';
import { DashboardWidgetComponent } from '../dashboard-widget/dashboard-widget.component';
import { LayoutPosition, RectanglePosition, WidgetConfig } from '../widget-default-setting';

@Component({
  selector: 'app-dashboard-designer',
  standalone: true,
  imports: [
    ConfigPanelComponent,
    DraggableDirective,
    NzTabsModule,
    NzIconDirective,
    NzGridModule,
    DroppableDirective,
    CdkDropListGroup,
    CdkDropList,
    CdkDrag,
    NgStyle,
    NgClass,
    ResizableModule,
    DashboardWidgetComponent
  ],
  templateUrl: './dashboard-designer.component.html',
  styleUrl: './dashboard-designer.component.less',
  styles: [
    `
      mwlResizable {
        box-sizing: border-box; // required for the enableGhostResize option to work
      }
    `
  ]
})
export class DashboardDesignerComponent implements AfterViewInit {
  @Output() readonly elementLoaded = new EventEmitter();
  @Input() widgetList: WidgetConfig[] = [];
  @Input() displayConfig: boolean = false;
  @ViewChild('rightDesign') rightDesign!: ElementRef<HTMLElement>;
  @ViewChild('horizontalSnapHelper') horizontalDragSnapHelper!: ElementRef<HTMLElement>;
  @ViewChild('verticalSnapHelper') verticalDragSnapHelper!: ElementRef<HTMLElement>;
  @ViewChild('northSnapHelper') northDragSnapHelper!: ElementRef<HTMLElement>;
  @ViewChild('southSnapHelper') southDragSnapHelper!: ElementRef<HTMLElement>;
  @ViewChild('westSnapHelper') westDragSnapHelper!: ElementRef<HTMLElement>;
  @ViewChild('eastSnapHelper') eastDragSnapHelper!: ElementRef<HTMLElement>;
  horizontalResizeSnapHelperPosition: string = 'none';
  verticalResizeSnapHelperPosition: string = 'none';
  northDragSnapHelperPosition: string = 'none';
  southDragSnapHelperPosition: string = 'none';
  westDragSnapHelperPosition: string = 'none';
  eastDragSnapHelperPosition: string = 'none';
  snap: boolean = true;
  snapMiddle: boolean = true;
  snapTolerance: number = 10;

  ngAfterViewInit(): void {
    this.elementLoaded.emit(this.rightDesign);
  }

  dragenter(event: CdkDragEnter<WidgetConfig[]>): void {
    let inElement = (event.item.previewContainer as HTMLElement).querySelector('.in') as HTMLElement;
    if (this.snap) {
      if (inElement.style.display != 'none') {
      }
    }
  }

  resizeLayoutPosition($event: NzSafeAny): void {
    const { tag, layout } = $event;
    const widget = this.widgetList.find(r => r.tag === tag)!;
    widget.layout = layout;
  }

  checkDragDropSnap(rect: RectanglePosition, widget: WidgetConfig): boolean {
    if (!this.snap) {
      return false;
    }

    let isSouth = true,
      isNorth = true,
      isWest = true,
      isEast = true,
      left = Math.round(rect.left),
      top = Math.round(rect.top),
      width = Math.round(rect.width),
      height = Math.round(rect.height),
      right = left + width,
      bottom = top + height,
      isNorthSnapped = false,
      isSouthSnapped = false,
      isWestSnapped = false,
      isEastSnapped = false;

    this.northDragSnapHelperPosition = 'none';
    this.southDragSnapHelperPosition = 'none';
    this.westDragSnapHelperPosition = 'none';
    this.eastDragSnapHelperPosition = 'none';

    this.widgetList.forEach(item => {
      if (widget != null && item == widget) {
        return;
      }

      let ele = document.querySelector(`${item.tag}`) as HTMLElement,
        pos = { top: ele.offsetTop, left: ele.offsetLeft },
        iLeft = Math.round(pos.left),
        iTop = Math.round(pos.top),
        iHMiddle = Math.round(iTop + ele.clientHeight / 2),
        iVMiddle = Math.round(iLeft + ele.clientWidth / 2),
        iRight = Math.round(iLeft + ele.clientWidth),
        iBottom = Math.round(iTop + ele.clientHeight);

      if (isNorth) {
        isNorthSnapped = this.confirmIsNorthSnap(isNorthSnapped, top, iTop, iBottom, iHMiddle, this.northDragSnapHelper, 'north');
      }

      if (isSouth) {
        isSouthSnapped = this.confirmIsNorthSnap(isSouthSnapped, bottom, iTop, iBottom, iHMiddle, this.northDragSnapHelper, 'south');
      }

      if (isWest) {
        isWestSnapped = this.confirmIsNorthSnap(isWestSnapped, left, iLeft, iRight, iVMiddle, this.northDragSnapHelper, 'south');
      }

      if (isEast) {
        isEastSnapped = this.confirmIsNorthSnap(isEastSnapped, right, iLeft, iRight, iVMiddle, this.northDragSnapHelper, 'south');
      }

      return isNorthSnapped && isSouthSnapped && isWestSnapped && isEastSnapped;
    });
    return false;
  }

  confirmIsNorthSnap(isNorthSnapped: boolean, top: number, iTop: number, iBottom: number, iHMiddle: number, snapHelper: ElementRef<HTMLElement>, positionType: string): boolean {
    let result: boolean = isNorthSnapped;
    if (!isNorthSnapped && Math.abs(top - iTop) <= this.snapTolerance) {
      snapHelper.nativeElement.style.top = `${iTop}px`;
      this.setPositionValue(positionType, 'top');
      result = true;
    }

    if (!isNorthSnapped && Math.abs(top - iBottom) <= this.snapTolerance) {
      snapHelper.nativeElement.style.top = `${iBottom}px`;
      this.setPositionValue(positionType, 'bottom');
      result = true;
    }

    if (this.snapMiddle && !isNorthSnapped && Math.abs(top - iHMiddle) <= this.snapTolerance) {
      snapHelper.nativeElement.style.top = `${iHMiddle}px`;
      this.setPositionValue(positionType, 'middle');
      result = true;
    }

    return result;
  }

  setPositionValue(positionType: string, value: string): void {
    switch (positionType) {
      case 'north':
        this.northDragSnapHelperPosition = value;
        break;
      case 'south':
        this.southDragSnapHelperPosition = value;
        break;
      case 'west':
        this.westDragSnapHelperPosition = value;
        break;
      case 'east':
        this.eastDragSnapHelperPosition = value;
        break;
    }
  }

  onResizeStart(event: ResizeEvent): void {}

  onResizeEnd(event: ResizeEvent): void {
    console.log('Element was resized', event);
    // recalculate the width of drag element
    //const addedWidth = event.rectangle
  }
}
